package com.zlyx.easy.core.utils;

import java.lang.invoke.MethodHandles;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;

import com.zlyx.easy.core.buffer.EasyBuffer;
import com.zlyx.easy.core.map.EasyMap;
import com.zlyx.easy.core.map.Maps;
import com.zlyx.easy.core.spring.NameDiscover;

/**
 * <p>
 * 方法操作工具
 * </p>
 *
 * @author 赵光
 * @since 2019年4月8日
 */
public final class MethodUtils {

	/**
	 * 获取当前对象的的类名
	 * 
	 * @param o
	 * @return
	 */
	public static String name(Method method) {
		return method == null ? null : method.getDeclaringClass().getName();
	}

	/**
	 * 获取当前对象的精简类名
	 * 
	 * @param o
	 * @return
	 */
	public static String simpleName(Method method) {
		return method == null ? null : method.getDeclaringClass().getSimpleName();
	}

	public static Object invokeDefaultMethod(Object proxy, Method method, Object[] args) throws Throwable {
		final Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class
				.getDeclaredConstructor(Class.class, int.class);
		if (!constructor.isAccessible()) {
			constructor.setAccessible(true);
		}
		final Class<?> declaringClass = method.getDeclaringClass();
		return constructor
				.newInstance(declaringClass,
						MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED | MethodHandles.Lookup.PACKAGE
								| MethodHandles.Lookup.PUBLIC)
				.unreflectSpecial(method, declaringClass).bindTo(proxy).invokeWithArguments(args);
	}

	public static boolean isDefaultMethod(Method method) {
		return (method.getModifiers() & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) == Modifier.PUBLIC
				&& method.getDeclaringClass().isInterface();
	}

	public static Type getReturnType(Method method) {
		Type type = method.getGenericReturnType();
		if (type instanceof ParameterizedType) {
			Type[] types = ((ParameterizedType) type).getActualTypeArguments();
			if (types.length > 0) {
				return types[0];
			}
		}
		return null;
	}

	/**
	 * 从spring框架中获得参数名称(ASM机制)
	 * 
	 * @param method
	 * @return
	 */
	public static String[] getParameterNames(Method method) {
		return NameDiscover.getParameterNames(method);
	}

	/**
	 * 获取方法的参数名称和参数map
	 * 
	 * @param method
	 * @return
	 */
	public static Map<String, Parameter> getParamterMap(Method method) {
		EasyMap<String, Parameter> parameterMap = Maps.newMap();
		String[] names = getParameterNames(method);
		Parameter[] paramaters = method.getParameters();
		for (int i = 0; i < paramaters.length; i++) {
			parameterMap.put(names[i], paramaters[i]);
		}
		return parameterMap;
	}

	/**
	 * 将某个方法的参数数组转换为参数名和参数值的Map形式
	 * 
	 * @param method
	 * @param args
	 * @return
	 */
	public static EasyMap<String, Object> getParamsMap(Method method, Object[] args) {
		EasyMap<String, Object> parameterMap = Maps.newMap();
		if (method != null) {
			try {
				String[] names = NameDiscover.getParameterNames(method);
				if (names != null) {
					for (int i = 0; i < names.length; i++) {
						parameterMap.put(names[i], args[i]);
					}
				}
			} catch (Exception ignored) {

			}
		}
		return parameterMap;
	}

	/**
	 * 获取被代理方法的真实方法对象
	 * 
	 * @param tClass
	 * @param method
	 * @return
	 */
	public static Method getRealMethod(Class<?> tClass, Method method) {
		try {
			method = tClass.getDeclaredMethod(method.getName(), method.getParameterTypes());
		} catch (Exception e) {
			Class<?> sClass = tClass.getSuperclass();
			if (sClass != Object.class) {
				method = getRealMethod(sClass, method);
			}
		}
		return method;
	}

//	/**
//	 * 获取被重写的父类方法
//	 * 
//	 * @param tClass
//	 * @param name
//	 * @return
//	 */
//	public static Method getOverrideMethod(Class<?> tClass, String name) {
//		Method method = null;
//		try {
//			method = tClass.getDeclaredMethod(name);
//		} catch (Exception e) {
//			Class<?> sClass = tClass.getSuperclass();
//			if (sClass != Object.class) {
//				method = getOverrideMethod(sClass, name);
//			}
//		}
//		return method;
//	}

	/**
	 * 获取有帮助的方法名(类路径.方法名称)
	 * 
	 * @param method
	 * @return
	 */
	public static String getHelpfulName(Method method) {
		return EasyBuffer.newString(method.getDeclaringClass().getName(), ".", method.getName());
	}

}
